﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
using JigLibX.Physics;
using JigLibX.Geometry;
using JigLibX.Collision;
using JigLibX.Math;

namespace LloydGame
{
    public class MapEditor : GameComponent
    {
        
        protected GameWorld m_gameWorld;
        protected String m_outPutfile;
        protected MouseState m_prevMouseState;
        protected KeyboardState m_prevKeyboardState;
        protected GameObject m_selectedGameObject;
        protected ConstraintWorldPoint m_objectController;
        protected ConstraintVelocity m_damperController;

        public GameObject selectedGameObject
        {
            get
            {
                return m_selectedGameObject;
            }
        }

        public MapEditor(Game p_game, GameWorld p_gameWorld, String p_outPutFile) : base(p_game)
        {
            m_gameWorld = p_gameWorld;
            m_outPutfile = p_outPutFile;
            m_objectController = new ConstraintWorldPoint();
            m_damperController = new ConstraintVelocity();
        }

        //Writes a map file in the working directory of the project
        private void WriteMap(String p_fileName)
        {
            try
            {
                using (StreamWriter sw = new StreamWriter(p_fileName))
                {
                    sw.WriteLine("# ObjectType pos(3) rot(3) scale(3) static_flag(1) optional_alias");
                    sw.WriteLine("# Angles are in degrees");
                    sw.WriteLine(" ");
                    foreach (GameObject gameObject in m_gameWorld.gameObjects)
                    {
                        int sFlag;
                        if (gameObject.staticFlag == true)
                        {
                            sFlag = 1;
                        }
                        else
                        {
                            sFlag = 0;
                        }
                        
                        sw.WriteLine(gameObject.objectType + "\t" +
                                     gameObject.position.X.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                                     gameObject.position.Y.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                                     gameObject.position.Z.ToString(CultureInfo.InvariantCulture.NumberFormat) + "\t" +
                                     (MathHelper.ToDegrees(gameObject.rotation.X)).ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                                     (MathHelper.ToDegrees(gameObject.rotation.Y)).ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                                     (MathHelper.ToDegrees(gameObject.rotation.Z)).ToString(CultureInfo.InvariantCulture.NumberFormat) + "\t" +
                                     gameObject.scale.X.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                                     gameObject.scale.Y.ToString(CultureInfo.InvariantCulture.NumberFormat) + " " +
                                     gameObject.scale.Z.ToString(CultureInfo.InvariantCulture.NumberFormat) + "\t" +
                                     sFlag + "\t" +
                                     gameObject.alias);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine("The file could not be read, or wasn't properly formated:");
                Console.WriteLine(e.Message);
            }

        }

        private class ImmovableSkinPredicate : CollisionSkinPredicate1
        {
            public override bool ConsiderSkin(CollisionSkin skin0)
            {
                if (skin0.Owner != null) //&& !skin0.Owner.Immovable)
                    return true;
                else
                    return false;
            }
        }

        private Vector3 RayTo(int x, int y)
        {
            Vector3 nearSource = new Vector3(x, y, 0);
            Vector3 farSource = new Vector3(x, y, 1);

            Matrix world = Matrix.CreateTranslation(0, 0, 0);

            Vector3 nearPoint = ((Game1)Game).graphics.GraphicsDevice.Viewport.Unproject(nearSource,
                ((Game1)Game).camera.proj,
                ((Game1)Game).camera.view, world);
            Vector3 farPoint = ((Game1)Game).graphics.GraphicsDevice.Viewport.Unproject(farSource,
                ((Game1)Game).camera.proj,
                ((Game1)Game).camera.view, world);

            Vector3 direction = farPoint - nearPoint;
            //direction.Normalize();
            return direction;
        }

        public override void Update(GameTime gameTime)
        {
            KeyboardState keyState = Keyboard.GetState();
            MouseState mouseState = Mouse.GetState();
            
            if (keyState.IsKeyDown(Keys.P))
            {
                WriteMap(m_outPutfile);
            }

            if (mouseState.LeftButton == ButtonState.Pressed && !(m_prevMouseState.LeftButton == ButtonState.Pressed))
            {

                Vector3 ray = RayTo(mouseState.X, mouseState.Y);
                float frac; CollisionSkin skin;
                Vector3 pos, normal;

                ImmovableSkinPredicate pred = new ImmovableSkinPredicate();

                ((Game1)Game).physSystem.CollisionSystem.SegmentIntersect(out frac, out skin, out pos, out normal,
                    new Segment(((Game1)Game).camera.position, ray * 1000.0f), pred);

                if (skin != null && (skin.Owner != null))
                {
                    
                    GameObject hej = m_gameWorld.GetObject(skin.Owner);
                    if (hej.selected == false && !m_gameWorld.gameObjectedSelected)
                    {
                        hej.selected = true;
                        m_gameWorld.gameObjectedSelected = true;
                        m_selectedGameObject = hej;
                    }
                    else if (hej.selected == true)
                    {
                        hej.selected = false;
                        m_gameWorld.gameObjectedSelected = false;
                        m_selectedGameObject = null;
                    }
                }
            }

            if (keyState.IsKeyDown(Keys.R) && !m_prevKeyboardState.IsKeyDown(Keys.R) && m_selectedGameObject != null)
            {
                m_gameWorld.markForRemoval(m_selectedGameObject);
                m_gameWorld.gameObjectedSelected = false;
                m_selectedGameObject = null;
            }
            

            if (keyState.IsKeyDown(Keys.U) && !m_prevKeyboardState.IsKeyDown(Keys.U) && m_selectedGameObject != null)
            {
                m_selectedGameObject.selected = false;
                m_gameWorld.gameObjectedSelected = false;
                m_selectedGameObject = null;
            }

            if (keyState.IsKeyDown(Keys.Y) && !m_prevKeyboardState.IsKeyDown(Keys.Y))
            {
                if (m_selectedGameObject != null && !m_selectedGameObject.staticFlag)
                {
                    if (!keyState.IsKeyDown(Keys.OemMinus))
                    {
                        m_selectedGameObject.body.Velocity += new Vector3(0.0f, 10.0f, 0.0f);
                    }
                    else
                    {
                        m_selectedGameObject.body.Velocity = new Vector3(0.0f, -10.0f, 0.0f);
                    }
                }
            }

            if (keyState.IsKeyDown(Keys.Z) && !m_prevKeyboardState.IsKeyDown(Keys.Z))
            {
                if (m_selectedGameObject != null && !m_selectedGameObject.staticFlag)
                {
                    if (!keyState.IsKeyDown(Keys.OemMinus))
                    {
                        m_selectedGameObject.body.Velocity = new Vector3(0.0f, 0.0f, 10.0f);
                    }
                    else
                    {
                        m_selectedGameObject.body.Velocity = new Vector3(0.0f, 0.0f, -10.0f);
                    }
                }
            }

            if (keyState.IsKeyDown(Keys.X) && !m_prevKeyboardState.IsKeyDown(Keys.X))
            {
                if (m_selectedGameObject != null && !m_selectedGameObject.staticFlag)
                {
                    if (!keyState.IsKeyDown(Keys.OemMinus))
                    {
                        m_selectedGameObject.body.Velocity = new Vector3(10.0f, 0.0f, 0.0f);
                    }
                    else
                    {
                        m_selectedGameObject.body.Velocity = new Vector3(-10.0f, 0.0f, 0.0f);
                    }
                }
            }

            m_prevMouseState = mouseState;
            m_prevKeyboardState = keyState;
        }
    }
}
